
#include "config.h"

#include "dushd.h"

#include "libbase.h"

static ECMBOOL	is_daemon;

static char	*server;
static ecm_uint16	port = 0;
ecm_dbg_t	dushd_dbg;

static char	*logfile;

ecm_ebc_t	ec = NULL;

const char	*modname;
const char	*dushd_clxdir;

const char	*comspec;

static void
dushd_shutdown(void)
{
	ebc_exit_app_loop(ec);
}

static void
signal_handler(ecm_signo_t signo)
{
	switch (signo) {
	case ECM_SIGINT:
	case ECM_SIGTERM:
		ECMVERBOSE("Received termination signal");
		dushd_shutdown();
		break;
	default:
		break;
	}
}

static void
usage(void)
{
	fprintf(stderr, "dushd\n");
	fprintf(stderr, "Usage: dushd [Options]\n");
	fprintf(stderr, "  -D : run as daemon\n");
	fprintf(stderr, "  -m <ebc module name>\n");
	fprintf(stderr, "  -s <ebc server ip>\n");
	fprintf(stderr, "  -p <ebc port>\n");
	fprintf(stderr, "  -l <log file>\n");
	fprintf(stderr, "  -v: verbose mode\n");
}

static void
setup_env(void)
{
	/* Load environment variables */
	/* Load clx dir */
	dushd_clxdir = ecm_strdup(ecm_default_clxdir());

	comspec = ecm_getenv("ComSpec");
	ecm_sscanf(ecm_getenv(ECM_EBC_PORT_ENV), "%hu", &port);
}

static ECMBOOL
parse_args(int argc, char *argv[])
{
	int	c;

	/* Parse options */
	while ((c = ecm_getopt(argc, argv, "Dhm:p:s:l:")) != -1) {
		switch(c) {
		case 'D':
			is_daemon = ECM_TRUE;
			break;
		case 'm': 
			modname = ecm_strdup(ecm_optarg);
			break;
		case 'p': 
			if (ecm_sscanf(ecm_optarg, "%hu", &port) != 1)
				return ECM_FALSE;
			ecm_setenv(ECM_EBC_PORT_ENV, "%hu", port);
			break;
		case 's':
			server = ecm_strdup(ecm_optarg);
			break;
		case 'l':
			logfile = ecm_strdup(ecm_optarg);
			break;
		case 'v':
			ecm_set_verbose_mode(ECM_TRUE);
			break;
		case 'h':
			usage();
			exit(0);
		}
	}

	return ECM_TRUE;
}

static void
setup_default(void)
{
	if (dushd_clxdir == NULL)
		dushd_clxdir = ecm_strdup(ecm_default_clxdir());
}

static ECMBOOL
setup_ebc_connection(void)
{
	ebc_err_t	err;
	ecm_uint32	count = 0;

	ECMVERBOSE("connecting to ebcd with port = %d", port);

again:
	if ((err = ebc_connect(server, port, modname, 5000, &ec)) != EBC_OK) {
		switch (err) {
		case -ERR_EBC_EXIST:
			ECMERR("another dushd already exist.");
			break;
		case -ERR_EBC_CONNECT:
			ECMERR("connect failed. retry after 1 sec..");
			ecm_sleep(1000);
			if (count++ < 7)
				goto again;
			ECMERR("too many connection failures. retry aborted..");

		default:
			ECMERR("EBC connection failed: %d", err);
			break;
		}
		return ECM_FALSE;
	}

	ECMVERBOSE("EBC connection established");

	if (ebc_ecb_add(ec, "execute", dushd_cb_execute, NULL) != EBC_OK ||
	    ebc_ecb_add(ec, "file", dushd_cb_file, NULL) != EBC_OK) {
		ECMERR("ebc setup error");
		ebc_close(ec);
		ec = NULL;
		return ECM_FALSE;
	}

	return ECM_TRUE;
}

#ifdef _WIN32
static void
dushd_stop_service(ecm_ptr_t ctx)
{
	ebc_exit_app_loop(ec);
}
#endif

static void
setup_logfile(void)
{
	FILE	*logfp = NULL;

	if (logfile)
		logfp = ecm_fopen(logfile, "a+");
	if (!is_daemon && logfp == NULL)
		logfp = ecm_stderr;
	ecm_set_output_file(logfp);
}

int
main(int argc, char *argv[], char *envs[])
{
	ecm_daemon_check("dushd", "ECM dushd", "ebcdx\0", main, argc, argv);
#ifdef _WIN32
	ecm_daemon_reg_stopper(dushd_stop_service, NULL);
#endif
	ebc_initialize();
	ecm_set_process_priority(1);

#ifdef ECM_DEBUG
	dushd_dbg = ecm_create_dbg();
#endif

	setup_env();

	ecm_signal(ECM_SIGINT, signal_handler);
	ecm_signal(ECM_SIGTERM, signal_handler);

	if (!parse_args(argc, argv)) {
		usage();
		return 1;
	}

	setup_logfile();

	ECMVERBOSE("\nStarting dushd...");

	setup_default();

	if (!setup_ebc_connection())
		return 3;

	dush_file_init();

	if (is_daemon)
		ecm_daemonize(dushd_clxdir, "dushd");

	ecm_daemon_set_running();

	if (ebc_app_loop(ec, 0) != EBC_OK)
		ECMERR("ebc_app_loop() error");

	ECMVERBOSE("disconnect from ebcd");

	ebc_close(ec);

	ecm_daemon_cleanup();

	ECMVERBOSE("dushd terminated");

	return 0;
}

#ifdef ECM_DEBUG

/* This is just a dummy for sr_fancy_print() linkage */
void
dummy_sr_fancy_print(void)
{
	sr_fancy_print(NULL, NULL, 2, "");
}

#endif
